import time

import logzero
import stackprinter
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor, QPalette
from PyQt5.QtWidgets import QGridLayout, QGroupBox, QLabel, QVBoxLayout, QWidget

import mengy_spac800
import mengy_spac800_bt
from helpers.mengy_bytes_helper import bytes2Int, getChineseStringLength, bytesPuttyPrint

logger = logzero.setup_logger("tabs.1.mea")


class Tab1_Mea(QWidget):
    def __init__(self, serRecvDir, logger=logger):
        super().__init__()
        self.initUI()
        self.refreshTime = time.time()
        self.serRecvDir = serRecvDir
        self.logger = logger
        self.logger.info("this is tab1 measure logger")
        self.setObjectName("tab1")
        layout = QGridLayout(self)
        layout.addWidget(self.prtUIGroupBox, 0, 0, 17, 2)
        layout.addWidget(self.meaUIGroupBox, 0, 2, 17, 5)
        layout.addWidget(self.didoGroupBox, 0, 7, 13, 1)
        layout.addWidget(self.deviceStatusGroupBox, 13, 7, 4, 1)

    def initUI(self):
        """初始化显示构件"""
        self.createPrtUIGroupBox()
        self.createMeaUIGroupBox()
        self.createDIDOGroupBox()
        self.createDeviceStatusGroupBox()

    def createPrtUIGroupBox(self):
        """保护监视界面初始化"""
        self.prtUIGroupBox = QGroupBox("保护监视")
        layout = QVBoxLayout(self.prtUIGroupBox)
        self.prtUI_Ws = []
        for _ in mengy_spac800.PRT_UI_CONFS:
            self.prtUI_Ws.append(QLabel(" " * 9))

        prtUgb = QGroupBox("电压量")
        uLayout = QGridLayout(prtUgb)
        for i, w in enumerate((0, 1, 2, 13, 14, 15)):
            uLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.PRT_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.PRT_UI_CONFS[w].name))), i, 0
            )
            uLayout.addWidget(self.prtUI_Ws[w], i, 1)

        prtIgb = QGroupBox("电流量")
        iLayout = QGridLayout(prtIgb)
        for i, w in enumerate((3, 4, 5, 16, 17, 18)):
            iLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.PRT_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.PRT_UI_CONFS[w].name))), i, 0
            )
            iLayout.addWidget(self.prtUI_Ws[w], i, 1)

        prtBgb = QGroupBox("不平衡量")
        bLayout = QGridLayout(prtBgb)
        for i, w in enumerate((6, 7, 8, 9, 10, 11, 12)):
            bLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.PRT_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.PRT_UI_CONFS[w].name))), i, 0
            )
            bLayout.addWidget(self.prtUI_Ws[w], i, 1)
        layout.addWidget(prtUgb)
        layout.addWidget(prtIgb)
        layout.addWidget(prtBgb)

    def createMeaUIGroupBox(self):
        """测量监视界面初始化"""
        self.meaUIGroupBox = QGroupBox("测量监视")
        layout = QGridLayout(self.meaUIGroupBox)
        self.meaUI_Ws = []
        for _ in mengy_spac800.MEA_UI_CONFS:
            self.meaUI_Ws.append(QLabel())

        meaIgb = QGroupBox("相电流")
        subLayout = QGridLayout(meaIgb)
        for i, w in enumerate((0, 1, 2, 3)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        meaUgb = QGroupBox("相电压")
        subLayout = QGridLayout(meaUgb)
        for i, w in enumerate((4, 5, 6, 7)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        meaUUgb = QGroupBox("线电压")
        subLayout = QGridLayout(meaUUgb)
        for i, w in enumerate((8, 9, 10, 11)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        meaCFgb = QGroupBox("功率因数")
        subLayout = QGridLayout(meaCFgb)
        for i, w in enumerate((12, 13, 14, 15, 16)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        meaPgb = QGroupBox("有功功率")
        subLayout = QGridLayout(meaPgb)
        for i, w in enumerate((17, 18, 19, 20)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        meaQgb = QGroupBox("无功功率")
        subLayout = QGridLayout(meaQgb)
        for i, w in enumerate((21, 22, 23, 24)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        meaSgb = QGroupBox("视在功率")
        subLayout = QGridLayout(meaSgb)
        for i, w in enumerate((25, 26, 27, 28)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        meaPPgb = QGroupBox("有功电度")
        subLayout = QGridLayout()
        for i, w in enumerate((29, 30, 31, 32)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)
        meaPPgb.setLayout(subLayout)
        meaQQgb = QGroupBox("无功电度")
        subLayout = QGridLayout(meaQQgb)
        for i, w in enumerate((33, 34, 35, 36)):
            subLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800.MEA_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800.MEA_UI_CONFS[w].name))), i, 0
            )
            subLayout.addWidget(self.meaUI_Ws[w], i, 1)

        layout.addWidget(meaIgb, 0, 0)
        layout.addWidget(meaUgb, 1, 0)
        layout.addWidget(meaUUgb, 2, 0)
        layout.addWidget(meaPgb, 0, 1)
        layout.addWidget(meaQgb, 1, 1)
        layout.addWidget(meaSgb, 2, 1)
        layout.addWidget(meaCFgb, 0, 2)
        layout.addWidget(meaPPgb, 1, 2)
        layout.addWidget(meaQQgb, 2, 2)

    def updatePrtUI(self):
        """更新保护测量显示"""
        raw = tuple(self.serRecvDir.get(key) for key in range(0x000E, 0x0020 + 1))
        if any((i is None for i in raw)):
            return
        prtData = tuple(bytes2Int(i) for i in raw)
        for i, conf in enumerate(mengy_spac800.PRT_UI_CONFS):
            valueStr = "{:{}} {}".format(prtData[i] / conf.rate, conf.format, conf.unit)
            self.prtUI_Ws[i].setText(valueStr)

    def updateMeaUI(self):
        """更新计量板测量显示"""
        if any((key not in self.serRecvDir.keys() for key in range(0x0023, 0x004F + 1))):
            return
        meaData = []
        try:
            for i in range(29):
                if i in (12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24):
                    signed = True
                else:
                    signed = False
                if i in (17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28):
                    j = (i - 17) * 2
                    dataBytes = self.serRecvDir.get(0x0034 + j) + self.serRecvDir.get(0x0035 + j)
                else:
                    dataBytes = self.serRecvDir.get(0x0023 + i)
                data = bytes2Int(dataBytes, signed=signed)
                meaData.append(data)
                self.logger.debug("index {} | data {} | dataBYtes {}".format(i, data, bytesPuttyPrint(dataBytes)))
        except Exception:
            self.logger.error(stackprinter.format())
        eeData = [bytes2Int(self.serRecvDir.get(0x004C + i, b"\x00")) for i in range(16)]
        for i in range(8):
            ee = (eeData[2 * i] << 16) + eeData[2 * i + 1]
            meaData.append(ee)
        for i, conf in enumerate(mengy_spac800.MEA_UI_CONFS):
            if abs(meaData[i]) < 10 ** 10:
                self.meaUI_Ws[i].setText("{:{}} {}".format(meaData[i] / conf.rate, conf.format, conf.unit))
            else:
                self.meaUI_Ws[i].setText("{:.4e} {}".format(meaData[i] / conf.rate, conf.unit))

    def createDIDOGroupBox(self):
        self.diStatusWs = []
        self.doStatusWs = []
        self.didoGroupBox = QGroupBox("开入开出状态")
        layout = QGridLayout(self.didoGroupBox)

        diGroupBox = QGroupBox("开入")
        subLayout = QGridLayout(diGroupBox)
        for i in range(mengy_spac800.DI_NUM):
            subLayout.addWidget(QLabel(str(i + 1)), i // 2, (i % 2) * 3, 1, 1)
            diLb = QLabel("0")
            diLb.setAutoFillBackground(True)
            diLb.setAlignment(Qt.AlignCenter)
            subLayout.addWidget(diLb, i // 2, 1 + (i % 2) * 3, 1, 2)
            self.diStatusWs.append(diLb)

        doGroupBox = QGroupBox("开出")
        subLayout = QGridLayout(doGroupBox)
        for i in range(mengy_spac800.DO_NUM_WITHOUT_LED):
            subLayout.addWidget(QLabel(str(i + 1)), i // 2, (i % 2) * 3, 1, 1)
            doLb = QLabel("分")
            doLb.setAutoFillBackground(True)
            doLb.setAlignment(Qt.AlignCenter)
            subLayout.addWidget(doLb, i // 2, 1 + (i % 2) * 3, 1, 2)
            self.doStatusWs.append(doLb)

        layout.addWidget(diGroupBox, 0, 0, 7, 1)
        layout.addWidget(doGroupBox, 7, 0, 5, 1)

    def updateDIUI(self):
        if self.serRecvDir.get(0x0008) is None:
            return
        diData = bytes2Int(self.serRecvDir.get(0x0008))
        for i, w in enumerate(self.diStatusWs):
            pal = w.palette()
            if diData & (1 << i):
                w.setText("1")
                pal.setColor(QPalette.Background, QColor(255, 0, 0))
            else:
                w.setText("0")
                pal.setColor(QPalette.Background, QColor(0, 255, 0))
            w.setPalette(pal)

    def updateDOUI(self):
        if self.serRecvDir.get(0x0009) is None:
            return
        doData = bytes2Int(self.serRecvDir.get(0x0009))
        for i, w in enumerate(self.doStatusWs):
            if doData & (1 << i):
                w.setText("合")
                w.setStyleSheet("background-color:#ff0000;")
            else:
                w.setText("分")
                w.setStyleSheet("background-color:#00ff00;")

    def createDeviceStatusGroupBox(self):
        self.deviceStatusGroupBox = QGroupBox("装置状态")
        layout = QGridLayout(self.deviceStatusGroupBox)

        layout.addWidget(QLabel("装置状态:"), 0, 0, 1, 1)
        self.runStatusLb = QLabel("正常")
        self.runStatusLb.setAutoFillBackground(True)
        self.runStatusLb.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.runStatusLb, 0, 1, 1, 1)

        layout.addWidget(QLabel("工作模式:"), 1, 0, 1, 1)
        self.workModelLb = QLabel("正常")
        self.workModelLb.setAutoFillBackground(True)
        self.workModelLb.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.workModelLb, 1, 1, 1, 1)

        layout.addWidget(QLabel("远方就地:"), 2, 0, 1, 1)
        self.RorLb = QLabel("就地")
        self.RorLb.setAutoFillBackground(True)
        self.RorLb.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.RorLb, 2, 1, 1, 1)

    def updateDeviceStatusUI(self):
        if self.serRecvDir.get(0x0004) is None:
            return
        status = bytes2Int(self.serRecvDir.get(0x0004))
        r = (status & (1 << 0)) >> 0
        pal = self.runStatusLb.palette()
        self.runStatusLb.setText(("正常", "故障")[r])
        pal.setColor(QPalette.Background, QColor(255 * r, 255 * (1 - r), 0))
        self.runStatusLb.setPalette(pal)

        w = (status & 0b110) >> 1
        pal = self.workModelLb.palette()
        self.workModelLb.setText(("正常", "旁路", "调试")[w])
        if w == 0:
            pal.setColor(QPalette.Background, QColor(0, 255, 0))
        elif w == 1:
            pal.setColor(QPalette.Background, QColor(0, 255, 255))
        elif w == 2:
            pal.setColor(QPalette.Background, QColor(255, 0, 0))
        self.workModelLb.setPalette(pal)

        pal = self.RorLb.palette()
        rol = (status >> 4) & 1
        self.RorLb.setText(("就地", "远方")[rol])
        if rol == 0:
            pal.setColor(QPalette.Background, QColor(0, 255, 0))
        else:
            pal.setColor(QPalette.Background, QColor(255, 0, 0))
        self.RorLb.setPalette(pal)

    def updateUnconditional(self):
        """无条件刷新界面显示部分"""
        pass

    def updateByTimer(self, timeout=5):
        if time.time() - self.refreshTime > timeout:
            self.updatePrtUI()
            self.updateMeaUI()
            self.updateDIUI()
            self.updateDOUI()
            self.updateDeviceStatusUI()
            self.refreshTime = time.time()

    def updateBySerialRecvBuff(self, changeAddrList):
        """报文数据发生变化时 更新对应显示构件"""
        if any(i in range(0x000E, 0x0020 + 1) for i in changeAddrList):
            self.updatePrtUI()
            self.refreshTime = time.time()
        if any(i in range(0x0023, 0x004F + 1) for i in changeAddrList):
            self.updateMeaUI()
            self.refreshTime = time.time()
        if 0x0008 in changeAddrList:
            self.updateDIUI()
            self.refreshTime = time.time()
        if 0x0009 in changeAddrList:
            self.updateDOUI()
            self.refreshTime = time.time()
        if 0x0004 in changeAddrList:
            self.updateDeviceStatusUI()
            self.refreshTime = time.time()

    def updateWhole(self):
        """更新全体显示构件"""
        self.updatePrtUI()
        self.updateMeaUI()
        self.updateDIUI()
        self.updateDOUI()
        self.updateDeviceStatusUI()
        self.refreshTime = time.time()


class Tab1_Mea_BT(Tab1_Mea):
    def createPrtUIGroupBox(self):
        """保护监视界面初始化"""
        self.prtUIGroupBox = QGroupBox("保护监视")
        layout = QVBoxLayout(self.prtUIGroupBox)
        self.prtUI_Ws = []
        for _ in mengy_spac800_bt.PRT_UI_CONFS:
            self.prtUI_Ws.append(QLabel(" " * 9))

        prtUgb = QGroupBox("线电压1")
        uLayout = QGridLayout(prtUgb)
        for i, w in enumerate((0, 1, 2, 10, 11, 12)):
            uLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800_bt.PRT_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800_bt.PRT_UI_CONFS[w].name))),
                i,
                0,
            )
            uLayout.addWidget(self.prtUI_Ws[w], i, 1)

        prtIgb = QGroupBox("线电压2")
        iLayout = QGridLayout(prtIgb)
        for i, w in enumerate((3, 4, 5, 13, 14, 15)):
            iLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800_bt.PRT_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800_bt.PRT_UI_CONFS[w].name))),
                i,
                0,
            )
            iLayout.addWidget(self.prtUI_Ws[w], i, 1)

        prtBgb = QGroupBox("抽取量")
        bLayout = QGridLayout(prtBgb)
        for i, w in enumerate((6, 7, 8, 9)):
            bLayout.addWidget(
                QLabel("{:^{}s}: ".format(mengy_spac800_bt.PRT_UI_CONFS[w].name, 7 - getChineseStringLength(mengy_spac800_bt.PRT_UI_CONFS[w].name))),
                i,
                0,
            )
            bLayout.addWidget(self.prtUI_Ws[w], i, 1)
        layout.addWidget(prtUgb)
        layout.addWidget(prtIgb)
        layout.addWidget(prtBgb)

    def updatePrtUI(self):
        """更新保护测量显示"""
        raw = tuple(self.serRecvDir.get(key) for key in range(0x000E, 0x001D + 1))
        if any((i is None for i in raw)):
            return
        prtData = tuple(bytes2Int(i) for i in raw)
        for i, conf in enumerate(mengy_spac800_bt.PRT_UI_CONFS):
            valueStr = "{:{}} {}".format(prtData[i] / conf.rate, conf.format, conf.unit)
            self.prtUI_Ws[i].setText(valueStr)

    def updateBySerialRecvBuff(self, changeAddrList):
        """报文数据发生变化时 更新对应显示构件"""
        if any(i in range(0x000E, 0x001D + 1) for i in changeAddrList):
            self.updatePrtUI()
            self.refreshTime = time.time()
        if any(i in range(0x0023, 0x004F + 1) for i in changeAddrList):
            self.updateMeaUI()
            self.refreshTime = time.time()
        if 0x0008 in changeAddrList:
            self.updateDIUI()
            self.refreshTime = time.time()
        if 0x0009 in changeAddrList:
            self.updateDOUI()
            self.refreshTime = time.time()
        if 0x0004 in changeAddrList:
            self.updateDeviceStatusUI()
            self.refreshTime = time.time()

    def createMeaUIGroupBox(self):
        """测量监视界面初始化"""
        super().createMeaUIGroupBox()
        self.meaUIGroupBox.setDisabled(True)
